import { useState, useEffect, useRef, useMemo, useCallback } from 'react'
import { findDOMNode } from 'react-dom';
import { FrameContentSty, PrintButtonSty, PrintResultSty, TitleSty } from './style';
import { Button, Divider } from 'antd';
import MaskingLayer from '@/components/MaskingLayer/index';

interface PrintProps {
  /** 是否显示*/
  isShow: boolean,
  /** 打印的元素*/
  children: React.ReactNode,
  /** 打印时的样式*/
  pageStyle?: string,
  /** 点击取消按钮*/
  handleCancel?: () => any
  /** 打印前触发的事*/
  onBeforePrint?: () => any,
  /** 打印后触发的事*/
  onAfterPrint?: () => void
}
export default function Print(props: PrintProps) {
  const {
    children,
    pageStyle = '',
    isShow,
    onBeforePrint = () => { },
    onAfterPrint = () => { },
    handleCancel = () => { }
  } = props
  const isPrinting = useRef(false);
  const printDom = useRef(null);

  const onPrint = useCallback(() => {
    if (document === null) {
      return
    }

    /** 打印的窗口页面*/
    const printWindow = document.createElement("iframe");
    printWindow.style.width = `${document.documentElement.clientWidth - 200}px`;
    printWindow.style.height = `${document.documentElement.clientHeight}px`;
    printWindow.style.position = "absolute";
    printWindow.style.top = `-${document.documentElement.clientHeight + 100}px`;
    printWindow.style.left = `-${document.documentElement.clientWidth + 100}px`;
    printWindow.id = "printWindow";
    //目的是让浏览器能够正确地渲染页面
    printWindow.srcdoc = "<!DOCTYPE html>";

    /** 清除上一次的iframe*/
    const documentPrintWindow = document.getElementById("printWindow");
    if (documentPrintWindow) {
      document.body.removeChild(documentPrintWindow);
    }

    document.body.appendChild(printWindow);

    /** 克隆的打印结点*/
    const contentNodes = findDOMNode(printDom.current);
    const contentNodesClone = (contentNodes as any).cloneNode(true);

    const globalStyleLinkNodes = document.querySelectorAll("link[rel='stylesheet']");
    const imgNodes = (contentNodesClone as Element).querySelectorAll("img");
    const videoNodes = (contentNodesClone as Element).querySelectorAll("video");

    //iframe加载完成时触发
    printWindow.onload = () => {
      /** 资源是否加载中*/
      let isLoading = true;
      let timer: any = null;

      let linkNum = 0;
      let imgNum = 0;
      let videoNum = 0;

      /** 文档对象*/
      const domDoc: Document = printWindow.contentDocument as Document

      if (domDoc) {
        domDoc.body.appendChild(contentNodesClone);
      }


      /** 改善页面打印的样式*/
      if (typeof pageStyle === 'string') {
        const styleEl = domDoc.createElement("style");
        styleEl.appendChild(domDoc.createTextNode(pageStyle));
        domDoc.head.appendChild(styleEl);
      } else {
        console.warn('pageStyle类型错误，应该为string')
      }

      //处理canvas,复制canvas
      const originalCanvas = (contentNodes as Element).querySelectorAll("canvas");
      const copiedCanvas = (domDoc).querySelectorAll("canvas");
      for (let i = 0; i < originalCanvas.length; ++i) {
        const sourceCanvas = originalCanvas[i];
        const targetCanvas = copiedCanvas[i];
        const targetCanvasCtx = targetCanvas.getContext("2d");
        if (targetCanvasCtx) {
          targetCanvasCtx.drawImage(sourceCanvas, 0, 0);
        }
      }

      // 图片
      for (let i = 0; i < imgNodes.length; i++) {
        const imgNodeItem = imgNodes[i];
        const imgSrc = imgNodeItem.getAttribute("src");

        if (imgSrc) {
          const img = new Image();
          img.src = imgSrc;
          img.onload = () => {
            imgNum++;
          }
        }
      }


      // 预加载视频
      for (let i = 0; i < videoNodes.length; i++) {
        const videoNodeItem = videoNodes[i];
        videoNodeItem.preload = 'auto';
        const videoPoster = videoNodeItem.getAttribute('poster')
        if (videoPoster) {
          const img = new Image();
          img.src = videoPoster;
          img.onload = () => {
            videoNum++;
          }
        } else {
          videoNodeItem.onloadeddata = () => {
            videoNum++;
          }
        }
      }

      //复制input
      const originalInputs = (contentNodes as HTMLElement).querySelectorAll('input');
      const copiedInputs = domDoc.querySelectorAll('input');
      for (let i = 0; i < originalInputs.length; i++) {
        copiedInputs[i].value = originalInputs[i].value;
      }

      // 复制 checkbox, radio checks
      const checkedSelector = 'input[type=checkbox],input[type=radio]';
      const originalCRs = (contentNodes as HTMLElement).querySelectorAll(checkedSelector);
      const copiedCRs = domDoc.querySelectorAll(checkedSelector);
      for (let i = 0; i < originalCRs.length; i++) {
        (copiedCRs[i] as HTMLInputElement).checked =
          (originalCRs[i] as HTMLInputElement).checked;
      }

      // 复制 select
      const selectSelector = 'select';
      const originalSelects = (contentNodes as HTMLElement).querySelectorAll(selectSelector);
      const copiedSelects = domDoc.querySelectorAll(selectSelector);
      for (let i = 0; i < originalSelects.length; i++) {
        copiedSelects[i].value = originalSelects[i].value;
      }


      //处理style
      const originalStyle = document.querySelectorAll("style");
      for (let i = 0; i < originalStyle.length; i++) {
        const styleItem = originalStyle[i];
        const newStyleItem = domDoc.createElement(styleItem.tagName);
        const sheet = (styleItem as HTMLStyleElement).sheet as CSSStyleSheet;
        if (sheet) {
          let styleCSS = "";
          try {
            const cssLength = sheet.cssRules.length;
            for (let j = 0; j < cssLength; ++j) {
              if (typeof sheet.cssRules[j].cssText === "string") {
                styleCSS += `${sheet.cssRules[j].cssText}\r\n`;
              }
            }
          } catch (error) {

          }
          newStyleItem.setAttribute("id", `react-to-print-${i}`);
          newStyleItem.appendChild(domDoc.createTextNode(styleCSS));
          domDoc.head.appendChild(newStyleItem);
        }
      }

      //处理link
      const originalLink = document.querySelectorAll("link[rel='stylesheet']");
      for (let i = 0; i < originalLink.length; i++) {
        const linkItem = originalLink[i];
        if (linkItem.getAttribute("href")) {
          if (linkItem.hasAttribute("disabled") === false) {
            const newLinkItem = domDoc.createElement(linkItem.tagName);
            for (let j = 0; j < linkItem.attributes.length; j++) {
              const attr = linkItem.attributes[j];
              if (attr) {
                newLinkItem.setAttribute(attr.nodeName, attr.nodeValue || "");
              }
            }
            newLinkItem.onload = () => {
              linkNum++;
            }
            domDoc.head.appendChild(newLinkItem);
          }
        }
      }

      /** 等待图片和视频加载完毕和link*/
      const readyToPrint = () => {
        if (imgNum === imgNodes.length && videoNum === videoNodes.length
          && linkNum === globalStyleLinkNodes.length
        ) {
          (printWindow as any).contentWindow.print()
          onAfterPrint()
          isPrinting.current = false
          isLoading = false
          cancelAnimationFrame(timer);
        }
        if (isLoading) {
          timer = requestAnimationFrame(readyToPrint)
        }
      }
      readyToPrint()
    }
  }, [pageStyle, onAfterPrint])


  /** 执行打印*/
  const startPrint = useCallback(() => {
    if (isPrinting.current) {
      console.warn('正在打印中')
      return
    }
    isPrinting.current = true
    const onBeforePrintOutput = onBeforePrint();
    if (onBeforePrintOutput && typeof onBeforePrintOutput.then === "function") {
      onBeforePrintOutput.then(() => {
        onPrint()
      }).catch((error: Error) => {

      });
    } else {
      onPrint()
    }
  }, [onPrint, onBeforePrint])

  const onCancel = useCallback(() => {
    handleCancel()
  }, [handleCancel])

  return (
    <>
      <MaskingLayer isShow={isShow}>
        <FrameContentSty>
          <TitleSty>打印预览</TitleSty>
          <PrintResultSty ref={printDom}>
            {
              children
            }
          </PrintResultSty>

          <Divider />

          <PrintButtonSty >
            <Button type='primary' onClick={startPrint}>打印</Button>
            <Button onClick={onCancel}>取消</Button>
          </PrintButtonSty>
        </FrameContentSty>
      </MaskingLayer>
    </>
  )
}